# $Id: ping.tcl 1520 2008-10-17 17:16:09Z sergei $
# Reply to XMPP Ping (XEP-0199) support

#############################################################################

namespace eval ping {
    custom::defvar options(ping) 0 \
	[::msgcat::mc "Ping server using urn:xmpp:ping requests."] \
	-group IQ \
	-type boolean \
	-command [namespace current]::start_all

    custom::defvar options(timeout) 30 \
	[::msgcat::mc "Reconnect to server if it does not reply (with result\
		       or with error) to ping (urn:xmpp:ping) request in\
		       specified time interval (in seconds)."] \
	-group IQ \
	-type integer \
	-command [namespace current]::start_all

    custom::defvar options(pong) 0 \
	[::msgcat::mc "Reply to ping (urn:xmpp:ping) requests."] \
	-group IQ \
	-type boolean

    variable sequence

    ::xmpp::iq::register get query urn:xmpp:ping [namespace current]::reply
    hook::add connected_hook [namespace current]::start
}

#############################################################################

proc ping::reply {xlib from child args} {
    variable options

    if {$options(pong)} {
	return [list result {}]
    } else {
	return [list error cancel service-unavailable]
    }
}

#############################################################################

proc ping::start_all {args} {
    variable options

    if {!$options(ping) || ($options(timeout) <= 0)} return

    foreach xlib [connections] {
	start $xlib
    }
}

#############################################################################

proc ping::start {xlib} {
    variable options
    variable sequence

    after cancel [namespace code [list start $xlib]]

    if {!$options(ping) || ($options(timeout) <= 0)} return

    if {![info exists sequence($xlib)]} {
	set sequence($xlib) 0
    }

    ::xmpp::sendIQ $xlib get \
	-query [::xmpp::xml::create ping -xmlns urn:xmpp:ping] \
	-timeout [expr {$options(timeout)*1000}] \
	-command [namespace code [list result $xlib [incr sequence($xlib)]]]
}

proc ping::result {xlib seq status xml} {
    variable options
    variable sequence

    if {!$options(ping) || ($options(timeout) <= 0)} return

    if {[lsearch -exact [connections] $xlib] < 0} return

    if {[string equal $status abort]} return

    if {$seq < $sequence($xlib)} return

    if {[string equal $status timeout]} {
	::xmpp::EndOfFile $xlib
	return
    }

    after [expr {$options(timeout)*1000}] [namespace code [list start $xlib]]
}

#############################################################################

